package com.we823.project.controller.repo;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.jquery.autocomplete.model.Suggestion;
import com.we823.project.common.utils.MaterialUtil;
import com.we823.project.common.web.BomUtil;
import com.we823.project.common.web.status.PermissionStatus;
import com.we823.project.controller.AbstractBaseController;
import com.we823.project.core.web.WebConstants;
import com.we823.project.model.product.PlanProcessModel;
import com.we823.project.model.product.ProcessInfo;
import com.we823.project.model.product.ProcessModel2;
import com.we823.project.model.repo.MaterialBomModel;
import com.we823.project.model.repo.MaterialModel;
import com.we823.project.repository.service.repo.MaterialBomService;
import com.we823.project.repository.service.repo.MaterialService;
import com.we823.project.repository.service.repo.ProcessService;
import com.we823.utils.web.RequestUtil;

@Controller
@RequestMapping(WebConstants.REPO_BOM)
public class MaterialBomController extends AbstractBaseController<MaterialBomModel> {

	private String baseUrl = WebConstants.REPO_BOM_TEMPLATE;
	
	private static final Logger logger = LoggerFactory.getLogger(MaterialBomController.class);
	
	@Autowired
	private MaterialService materialService;
	
	private @Resource ProcessService processService;
	
	private MaterialBomService materialBomService;
	@Autowired
	public MaterialBomController(MaterialBomService materialBomService) {
		super(materialBomService);
		this.materialBomService = materialBomService;
		super.baseUrl = baseUrl;
		super.entityName = "bom";
		setResourceIdentity("data:bom");
	}

	@Override
	public Page<MaterialBomModel> getData(PageRequest pageRequest,
			HttpServletRequest request, Model model, boolean pageable) {
		Page<MaterialBomModel> materialBomPage = null;
		String code = RequestUtil.getValueByParam(request, "code");
		if(StringUtils.isBlank(code)) {
			if(pageable) {
				materialBomPage = materialBomService.findAll(pageRequest);
			}else {
				materialBomPage = new PageImpl<>(materialBomService.findAll());
			}
		}else {
			if(pageable) {
				materialBomPage = materialBomService.findByCode(code,pageRequest);
			}else {
				materialBomPage = new PageImpl<>(materialBomService.findByCode(code));
			}
		}
		if(materialBomPage!=null) {
			fillInfo(materialBomPage);
		}
		return materialBomPage;
	}

	@Override
	public String add(HttpServletRequest request, MaterialBomModel entity,
			Model model, BindingResult bindingResult,RedirectAttributes redirectAttributes) {
		check(PermissionStatus.CREATE);
		if (entity!=null) {
			int currentIndex = RequestUtil.getValueByParam(request, "current_index", 0);
			if(currentIndex>0) {
				String code = entity.getCode();
				Map<String, MaterialBomModel> submaterialMap = materialBomService.getMapByCode(code);
				List<MaterialBomModel> materialBomModels = new ArrayList<>();
				for (int index = 1; index <= currentIndex; index++) {
					int id = RequestUtil.getValueByParam(request, "id_"+index, 0);
					String materialCode = RequestUtil.getValueByParam(request, "materialCode_"+index);
					Float needNum = RequestUtil.getFloatValueByParam(request, "needNum_"+index);
					String spec = RequestUtil.getValueByParam(request, "spec_"+index);
					String storeType = RequestUtil.getValueByParam(request, "storeType_"+index);
					String boxNum = RequestUtil.getValueByParam(request, "boxNum_"+index);
					
					MaterialBomModel materialBomModel = null;
					if(id>0) {
						materialBomModel = submaterialMap.get(materialCode);
						materialBomModel.setEdittime(new Date());
					}else {
						
						materialBomModel = new MaterialBomModel();
						materialBomModel.setCode(code);
						materialBomModel.setMaterialCode(materialCode);
						materialBomModel.setAddtime(new Date());
					}
					
					materialBomModel.setNeedNum(needNum);
					materialBomModel.setSpecial(spec);
					materialBomModel.setStoreType(storeType);
					materialBomModel.setBoxNum(boxNum);
					
					materialBomModels.add(materialBomModel);
					
				}
				
				materialBomService.save(materialBomModels);
				
				redirectAttributes.addFlashAttribute(WebConstants.MESSAGE,"添加成功");
			}
		}
		return listUrl;
	}
	private void fillInfo(Page<MaterialBomModel> materialBomPage) {
		if(materialBomPage!=null) {
			List<MaterialBomModel> materialBomModels = materialBomPage.getContent();
			if(materialBomModels!=null && materialBomModels.size()>0) {
				Map<String, MaterialModel> map = materialService.map();
				if(map!=null) {
					for (MaterialBomModel materialBomModel : materialBomModels) {
						String code = materialBomModel.getCode();
						MaterialModel mainMaterialModel = map.get(code);
						if(mainMaterialModel!=null) {
							materialBomModel.setName(mainMaterialModel.getModel()+" "+mainMaterialModel.getSpecification());
						}
						
						String materialCode = materialBomModel.getMaterialCode();
						MaterialModel materialModel = map.get(materialCode);
						if(materialModel!=null) {
							BomUtil.copyInfo(materialBomModel, materialModel);
						}
					}
				}
			}
		}
		
	}

	@RequestMapping("getList")
	@ResponseBody
	public Model getList(HttpServletRequest request,Model model) {
		check(PermissionStatus.VIEW);
		String code = RequestUtil.getValueByParam(request, "code");
		if(!StringUtils.isBlank(code)) {
			MaterialModel materialModel = BomUtil.findBomByCode(code,materialService,materialBomService);
			model.addAttribute("mainMaterial",materialModel);
		}
		return model;
	}
	
	/**
	 * action s:autocomplete o:single bom tree:bom tree
	 * @param request
	 * @param model
	 * @return
	 */
	@RequestMapping("findBom")
	@ResponseBody
	public Model findBom(HttpServletRequest request,Model model) {
		String query = RequestUtil.getValueByParam(request, "query");
		String action = RequestUtil.getValueByParam(request, "action");
		PageRequest pageRequest = new PageRequest(0, 20);
		if ("s".equals(action)) {
			Page<MaterialBomModel> bomPage = materialBomService.findByCodeContaining(query,pageRequest);
			if (bomPage!=null) {
				List<Suggestion> suggestions = Lists.newArrayList();
				List<MaterialBomModel> bomModels = bomPage.getContent();
				Suggestion suggestion = null;
				for (MaterialBomModel materialBomModel : bomModels) {
					suggestion = new Suggestion();
					suggestion.setValue(materialBomModel.getCode());
					suggestion.setData(materialBomModel.getModel());
					suggestions.add(suggestion);
				}
				model.addAttribute("suggestions",suggestions);
			}
		} else if("tree".equals(action)){
			//建立BOM结构
			buildBomTree(request,model);
		}else {
			String code = RequestUtil.getValueByParam(request, "code");
			List<MaterialBomModel> materialBomModels = materialBomService.findByCode(code);
			if (materialBomModels!=null && materialBomModels.size()>0) {
				model.addAttribute("materialBom",materialBomModels.get(0));
			}
		}
		
		return model;
	}
	
	@RequestMapping("getProperties")
	@ResponseBody
	public Model getBomProperties(HttpServletRequest request,Model model) {
		String process = RequestUtil.getValueByParam(request, "process");
		String materialCode = RequestUtil.getValueByParam(request, "materialCode");
		String destCode = RequestUtil.getValueByParam(request, "destCode");
		
		List<MaterialBomModel> materialBomModels = null;
		switch (process) {
		case "绝缘":
			materialBomModels = materialBomService.findByMaterialCodeAndCode(materialCode,destCode);
			break;
		case "成缆":
			materialBomModels = materialBomService.findByProcessAndCode(process,destCode);
		default:
			materialBomModels = materialBomService.findByProcessAndCode(process,destCode);
			break;
		}
		if ("绝缘".equals(process) && materialBomModels!=null && materialBomModels.size()>0) {
			model.addAttribute("materialBoms",Lists.newArrayList(materialBomModels.get(0)));
		}else {
			model.addAttribute("materialBoms",materialBomModels);
		}
		return model;
	}
	@RequestMapping("init")
	public String init(HttpServletRequest request,Model model) {
		List<MaterialBomModel> materialBomModels = materialBomService.findAll();
		if (materialBomModels!=null) {
			int count=0;
			for (MaterialBomModel materialBomModel : materialBomModels) {
				String materialModel = materialBomModel.getMaterialModel();
				String materialDesc = materialBomModel.getMaterialDesc();
				String colorString = MaterialUtil.getBomColor(materialDesc);
				
				String materialCode = materialBomModel.getMaterialCode();
				if (StringUtils.isEmpty(materialCode)) {
					MaterialModel material = materialService.findByFullnameAndColor(materialModel, colorString);
					if (material!=null) {
						materialBomModel.setMaterialCode(material.getCode());
						materialBomService.update(materialBomModel);
						
						//System.out.println("update:"+materialBomModel.getId()+" "+materialModel+" -- "+materialDesc + " -- "+colorString + " -- code:"+material.getCode());
					}else {
						System.out.println(materialBomModel.getId()+" "+"cannot find:"+materialModel+" -- "+materialDesc + " -- "+colorString);
						count++;
					}
				}else {
					//System.out.println(materialBomModel.getId()+" "+"code not null:"+materialCode);
				}
			}
			System.out.println(count);
		}
		return listUrl;
	}
	
	private void buildBomTree(HttpServletRequest request, Model model) {
		String code = RequestUtil.getValueByParam(request, "code");
		float planNum = RequestUtil.getFloatValueByParam(request, "planNum", 0);
		
		List<MaterialBomModel> materialBomModels = materialBomService.findByCode(code);
		if (materialBomModels!=null && materialBomModels.size()>0) {
			
			LinkedListMultimap<String, MaterialBomModel> materialBomMultimap = LinkedListMultimap.create();
			for (MaterialBomModel materialBomModel : materialBomModels) {
				materialBomMultimap.put(materialBomModel.getProcess(), materialBomModel);
			}
			List<ProcessInfo> processInfos = Lists.newArrayList();
			//buildProcess(materialBomModels, processInfos,1,1,null,planNum);
			buildProcessEx(materialBomMultimap,processInfos,1,1,null,planNum);
			Collections.sort(processInfos);
			model.addAttribute("processInfos",processInfos);
			if (logger.isDebugEnabled()) {
				if (processInfos!=null) {
					for (ProcessInfo processInfo : processInfos) {
						logger.debug(processInfo.toString());
					}
				}
			}

		}
		
	}
	private void buildProcessEx(LinkedListMultimap<String, MaterialBomModel> materialBomMultimap,
			List<ProcessInfo> processInfos, int count, int deep, MaterialBomModel parentBom,
			float planNum) {
		if (materialBomMultimap!=null && materialBomMultimap.size()>0) {
			Object[] processSet = materialBomMultimap.keySet().toArray();
			ProcessInfo processInfo = null;
			String nextProcess = "无";
			String preProcess = "无";
			List<String> preProcessList = null;
			int mapSize = processSet.length;
			int orderid = 1;
			for (int index = 0; index < mapSize; index++) {
				processInfo = new ProcessInfo();
				String process = (String) processSet[index];
				preProcessList = Lists.newArrayList();
				//当前工序中的BOM
				List<MaterialBomModel> materialBomModels = materialBomMultimap.get(process);
				if (materialBomModels!=null && materialBomModels.size()>0) {
					int bomIndex = 1;
					for (MaterialBomModel materialBomModel : materialBomModels) {
						//根据当前工序中所需的物料查找得到的子BOM
						List<MaterialBomModel> subMaterialBomModels = materialBomService.findByCode(materialBomModel.getMaterialCode());
						if (subMaterialBomModels!=null && subMaterialBomModels.size()>0) {
							LinkedListMultimap<String, MaterialBomModel> subMaterialBomMultimap = LinkedListMultimap.create();
							//获取到子BOM中的所有工序
							for (MaterialBomModel subBomModel : subMaterialBomModels) {
								subMaterialBomMultimap.put(subBomModel.getProcess(), subBomModel);
							}
							//将子工序中的最后一道工序加入
							preProcessList.add(getLastSubProcess(subMaterialBomMultimap));
							int subCount = count * 100 + bomIndex;
							float totalNum = materialBomModel.getNeedNum() * planNum;
							buildProcessEx(subMaterialBomMultimap, processInfos, subCount, deep+1, materialBomModel, totalNum);
							bomIndex++;
						}
					}
				}
				
				if(parentBom!=null && index==mapSize-1) {
					nextProcess = parentBom.getProcess();
				}else {
					if (index<mapSize-1) {
						nextProcess = (String) processSet[index+1];
					}else {
						nextProcess = "无";
					}
				}
				if (index==0) {
					if (preProcessList.size()==0) {
						preProcess = "无";
						preProcessList.add(preProcess);
					}
				}else {
					preProcess = (String) processSet[index-1];
					preProcessList.add(preProcess);
				}
				
				processInfo.setName(process);
				processInfo.setPreProcessList(preProcessList);
				processInfo.setNextProcess(nextProcess);
				
				processInfo.setCount(count);
				processInfo.setOrderid(orderid++);
				processInfo.setDeep(deep);
				if (materialBomModels!=null && materialBomModels.size()>0) {
					MaterialBomModel materialBomModel = materialBomModels.get(0);
					processInfo.setCode(materialBomModel.getCode());
					processInfo.setModel(materialBomModel.getModel());
					
					if(parentBom!=null && index==mapSize-1) {
						processInfo.setDestCode(parentBom.getCode());
						processInfo.setDestModel(parentBom.getModel());
					}else {
						processInfo.setDestCode(materialBomModel.getCode());
						processInfo.setDestModel(materialBomModel.getModel());
					}
					
					processInfo.setTotalNum(planNum);
					MaterialModel materialModel = materialService.findByCode(materialBomModel.getCode());
					if (deep==1) {
						if (materialModel!=null) {
							processInfo.setDesc(materialModel.getColor());
						}
					}else {
						processInfo.setDesc(parentBom.getMaterialDesc());
					}
					if (materialModel!=null) {
						processInfo.setUnit(materialModel.getUnit());
					}
				}
				
				String description = "";
				if ("无".equals(nextProcess)) {
					description = processInfo.getDestCode()+" "+"成品使用";
				}else {
					description = processInfo.getDestCode()+" "+processInfo.getNextProcess() + "使用";
				}
				processInfo.setDescription(description);
				processInfos.add(processInfo);
			}
		}
	}

	private String getLastSubProcess(
			LinkedListMultimap<String, MaterialBomModel> subMaterialBomMultimap) {
		if (subMaterialBomMultimap!=null && subMaterialBomMultimap.size()>0) {
			Set<String> processSet = subMaterialBomMultimap.keySet();
			Object[] processes = processSet.toArray();
			return processes[processes.length-1].toString();
		}
		return null;
	}

	/**
	 * 
	 * @param materialBomModels
	 * @param processInfos
	 * @param count bom计数
	 * @param deep bom的级别，1为最高，以此类推，排序后1排在最后生产
	 * @param parentBom 父类BOM
	 * @param planNum 计划生产长度
	 */
	private String buildProcess(List<MaterialBomModel> materialBomModels,
			List<ProcessInfo> processInfos,int count,int deep,MaterialBomModel parentBom,float planNum) {
		ProcessInfo processInfo = null;
		int orderid = 1;
		String nextProcess = "无";
		String preProcess = "无";
		int index=1; //对于存在子bom的计数器
		for (MaterialBomModel materialBomModel : materialBomModels) {
			
			
			List<MaterialBomModel> subBomModels = materialBomService.findByCode(materialBomModel.getMaterialCode());
			if(subBomModels!=null && subBomModels.size()>0) {
				int subCount = count * 100 * index + index;
				float totalNum = materialBomModel.getNeedNum() * planNum;
				preProcess = buildProcess(subBomModels,processInfos,subCount,deep+1,materialBomModel,totalNum);
				index++;
			}
			
			processInfo = new ProcessInfo();
			processInfo.setName(materialBomModel.getProcess());
			processInfo.setCode(materialBomModel.getCode());
			processInfo.setModel(materialBomModel.getModel());
			processInfo.setCount(count);
			processInfo.setOrderid(orderid);
			processInfo.setDeep(deep);
			//processInfo.setPreProcess(preProcess);
			MaterialModel materialModel = materialService.findByCode(materialBomModel.getCode());

			String desc = "";
			
			if (materialModel!=null) {
				desc = (deep==1) ? materialModel.getColor() : parentBom.getMaterialDesc();
				if (deep==1) {
					processInfo.setDestCode(materialBomModel.getCode());
					processInfo.setDestModel(materialBomModel.getModel());
				}else {
					processInfo.setDestCode(parentBom.getCode());
					processInfo.setDestModel(parentBom.getModel());
				}
			}
			processInfo.setDesc(desc);
			processInfo.setTotalNum(planNum);
			processInfo.setUnit(materialModel.getUnit());
			/*
			 * 设置后续工序
			 */
			if (parentBom!=null) {
				nextProcess = parentBom.getProcess();
			}
			
			processInfo.setNextProcess(nextProcess);
			if (!processInfos.contains(processInfo)) {
				processInfos.add(processInfo);
				preProcess = processInfo.getName();
				orderid++;
			}
			
		}
		
		return preProcess;
		
	}

	private void buildBomTree2(HttpServletRequest request, Model model) {
		String code = RequestUtil.getValueByParam(request, "code");
		List<MaterialBomModel> materialBomModels = materialBomService.findByCode(code);
		if(materialBomModels!=null && materialBomModels.size()>0) {
			fillSubBoms(materialBomModels);
			Map<String, List<MaterialBomModel>> processMap = Maps.newHashMap();
			for (MaterialBomModel materialBomModel : materialBomModels) {
				String name = materialBomModel.getProcess();
				List<MaterialBomModel> processBomModels = processMap.get(name);
				if (processBomModels==null) {
					processBomModels = Lists.newArrayList(materialBomModel);
					processMap.put(name, processBomModels);
				}else {
					processBomModels.add(materialBomModel);
				}
			}
			
			List<ProcessModel2> processModels = Lists.newArrayList();
			
			Set<String> processSet = processMap.keySet();
			Integer orderid = 0;
			for (String processName : processSet) {
				ProcessModel2 processModel = new ProcessModel2(processName, processMap.get(processName), orderid++);
				processModel.setDeep(0);
				processModels.add(processModel);
			}
			
			List<MaterialBomModel> bomTree = Lists.newArrayList();
			List<PlanProcessModel> planProcessList = Lists.newArrayList();
			//buildBomTreeList(planProcessList,materialBomModels);
			
			List<ProcessInfo> processInfos = Lists.newArrayList();
			int bomNo=1;
			
			MaterialBomModel destBomModel = new MaterialBomModel();
			buildProcessInfo(processInfos,materialBomModels,1,bomNo,destBomModel);
			
			//model.addAttribute("processModels",processModels);
			//model.addAttribute("bomTreeList",bomTree);
			model.addAttribute("processInfos",processInfos);
			
			Collections.sort(processInfos);
			int index=1;
			for (ProcessInfo processInfo : processInfos) {
				System.out.println((index++)+"  "+processInfo.toString());
			}
			System.out.println(processInfos.size());
		}

	}

	private void buildProcessInfo(List<ProcessInfo> processInfos,List<MaterialBomModel> materialBomModels,int deep,int bomNum,MaterialBomModel destBomModel) {
		if (materialBomModels!=null && materialBomModels.size()>0) {
			ProcessInfo processInfo = null;
			int orderid = 1;
			int index = 1;
			for (MaterialBomModel materialBomModel : materialBomModels) {
					processInfo = new ProcessInfo();
					processInfo.setName(materialBomModel.getProcess());
					processInfo.setOrderid(orderid);
					processInfo.setDeep(deep);
					processInfo.setCount(bomNum);
	
					if (!processInfos.contains(processInfo)) {
						processInfos.add(processInfo);
						orderid++;
					}
					
					List<MaterialBomModel> subBomModels = materialBomModel.getSubMaterialBoms();
					if (subBomModels!=null && subBomModels.size()>0) {
						int subBomNum = bomNum * 100 * index + index;
						buildProcessInfo(processInfos, subBomModels, deep+1,subBomNum,materialBomModel);
						index++;
					}
			}
			
		}
		
	}

	private void buildBomTreeList(List<PlanProcessModel> planProcessModels,
			List<MaterialBomModel> materialBomModels) {
		if (materialBomModels!=null && materialBomModels.size()>0) {
			PlanProcessModel planProcessModel = null;
			for (MaterialBomModel materialBomModel : materialBomModels) {
				planProcessModel = new PlanProcessModel(materialBomModel, 5000);
				planProcessModels.add(planProcessModel);
				List<MaterialBomModel> subBomModels = materialBomModel.getSubMaterialBoms();
				if (subBomModels!=null) {
					buildBomTreeList(planProcessModels, subBomModels);
				}
			}
		}
		
	}

	/**
	 * 填充子BOM，根据code查找
	 * @param materialBomModels
	 */
	private void fillSubBoms(List<MaterialBomModel> materialBomModels) {
		if (materialBomModels!=null) {
			for (MaterialBomModel materialBomModel : materialBomModels) {
				List<MaterialBomModel> subBomModels = materialBomService.findByCode(materialBomModel.getMaterialCode());
				if (subBomModels!=null && subBomModels.size()>0) {
					fillSubBoms(subBomModels);
					materialBomModel.setSubMaterialBoms(subBomModels);
				}else {
					continue;
				}
			}
		}
		
	}

	public MaterialService getMaterialService() {
		return materialService;
	}

	public void setMaterialService(MaterialService materialService) {
		this.materialService = materialService;
	}

}
